home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / MacOptionPaneUI.java < prev    next >
Text File  |  1998-06-30  |  18KB  |  576 lines

  1. /*
  2.  * @(#)MacOptionPaneUI.java    1.6 98/02/02
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. package com.sun.java.swing.plaf.mac;
  23.  
  24. import com.sun.java.swing.*;
  25. import com.sun.java.swing.plaf.basic.*;
  26. import com.sun.java.swing.plaf.ComponentUI;
  27. import java.awt.*;
  28. import java.awt.event.*;
  29. import java.io.*;
  30.  
  31. /**
  32.  * Provides the CDE/Mac look and feel for a JOptionPane.
  33.  * <p>
  34.  * Warning: serialized objects of this class will not be compatible with
  35.  * future swing releases.  The current serialization support is appropriate
  36.  * for short term storage or RMI between Swing1.0 applications.  It will
  37.  * not be possible to load serialized Swing1.0 objects with future releases
  38.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  39.  * baseline for the serialized form of Swing objects.
  40.  *
  41.  * @version @(#)MacOptionPaneUI.java    1.0 11/24/97
  42.  * @author Symantec
  43.  */
  44. public class MacOptionPaneUI extends BasicOptionPaneUI
  45. {
  46.     /** Option names for YES_NO_OPTION. */
  47.     public static final String[] yesNoOptions = { "No", "Yes" };
  48.     public static final int[] yesNoReturnValue = { JOptionPane.NO_OPTION, JOptionPane.YES_OPTION };
  49.     /** Options names for YES_NO_CANCEL_OPTION. */
  50.     public static final String[] yesNoCancelOptions = { "Cancel", "No", "Yes" };
  51.     public static final int[] yesNoCancelReturnValue = { JOptionPane.CANCEL_OPTION, JOptionPane.NO_OPTION, JOptionPane.YES_OPTION };
  52.     /** Default option names, when none are supplied. */
  53.     public static final String[] defaultOptions = { "OK" };
  54.     /** Option names for OK_CANCEL_OPTION. */
  55.     public static final String[] okCancelOptions = { "Cancel", "OK" };
  56.     public static final int[] okCancelReturnValue = { JOptionPane.CANCEL_OPTION, JOptionPane.OK_OPTION };
  57.  
  58.     private boolean hasIcon = false;
  59.  
  60.     /**
  61.       * Creates a new MacOptionPaneUI instance.
  62.       */
  63.     public static ComponentUI createUI(JComponent x) {
  64.     return new MacOptionPaneUI();
  65.     }
  66.  
  67.     /**
  68.      * Returns the buttons to display from the JOptionPane the receiver is
  69.      * providing the look and feel for. If the JOptionPane has options
  70.      * set, they will be provided, otherwise if the optionType is
  71.      * YES_NO_OPTION, yesNoOptions is returned, if the type is
  72.      * YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise
  73.      * defaultButtons are returned.
  74.      * 
  75.      * Overrides the basic UI implementation because the buttons are in the
  76.      * opposite order on the Mac
  77.      */
  78.     public Object[] getButtons() {
  79.     if (optionPane != null) {
  80.         Object[]           suppliedOptions = optionPane.getOptions();
  81.  
  82.         if (suppliedOptions == null) {
  83.         int            type = optionPane.getOptionType();
  84.  
  85.         if (type == JOptionPane.YES_NO_OPTION)
  86.             return MacOptionPaneUI.yesNoOptions;
  87.         else if (type == JOptionPane.YES_NO_CANCEL_OPTION)
  88.             return MacOptionPaneUI.yesNoCancelOptions;
  89.         else if (type == JOptionPane.OK_CANCEL_OPTION)
  90.             return MacOptionPaneUI.okCancelOptions;
  91.         return MacOptionPaneUI.defaultOptions;
  92.         }
  93.         return suppliedOptions;
  94.     }
  95.     return null;
  96.     }
  97.  
  98.     /**
  99.      * Messaged when a JButton as created from validateComponent is clicked
  100.      * Invokes setValue on the JOptionPane with the appropriate value.
  101.      * <p>
  102.      * If you are creating your own look and feel and subclassing this
  103.      * be sure to set the value to an Integer value representing
  104.      * YES_OPTION, NO_OPTION or CANCEL_OPTION.
  105.      */
  106.     public void createdButtonFired(int buttonIndex) {
  107.     if (optionPane != null) {
  108.         Object[]        options = optionPane.getOptions();
  109.  
  110.         if (options == null) {
  111.         int        messageType = optionPane.getOptionType();
  112.         int        returnVal;
  113.  
  114.         if (messageType == JOptionPane.YES_NO_OPTION)
  115.             returnVal = yesNoReturnValue[buttonIndex];
  116.         else if (messageType == JOptionPane.OK_CANCEL_OPTION)
  117.             returnVal = okCancelReturnValue[buttonIndex];
  118.         else if (messageType == JOptionPane.YES_NO_CANCEL_OPTION)
  119.             returnVal = yesNoCancelReturnValue[buttonIndex];
  120.         else
  121.             returnVal = JOptionPane.OK_OPTION;
  122.  
  123.         // OK or Yes button was pressed in an input dialog
  124.         //  (!!! duplicating the strange BasicUI behaviour of not reseting for default options !!!)
  125.         if (inputComponent != null && returnVal == JOptionPane.OK_OPTION &&
  126.             messageType != JOptionPane.DEFAULT_OPTION)
  127.             resetInputValue();
  128.  
  129.         optionPane.setValue(new Integer(returnVal));
  130.         }
  131.         else
  132.         optionPane.setValue(options[buttonIndex]);
  133.     }
  134.     }
  135.  
  136.     /**
  137.      * Returns the icon to use for the passed in type.
  138.      *
  139.      * No icon for Mac input dialogs (no question icon)
  140.      */
  141.     public Icon getIconForType(int messageType) {
  142.     switch(messageType) {
  143.     case 0:
  144.         return UIManager.getIcon("OptionPane.errorIcon");
  145.     case 1:
  146.         return UIManager.getIcon("OptionPane.informationIcon");
  147.     case 2:
  148.         return UIManager.getIcon("OptionPane.warningIcon");
  149.     }
  150.     return null;
  151.     }
  152.  
  153.     /**
  154.      * Make the dialog box non-resizeable - like they ought to be on the Mac
  155.      */
  156.     public void selectInitialValue() {
  157.     super.selectInitialValue();
  158.  
  159.     Container dialog = optionPane.getParent();
  160.     while (dialog != null) {
  161.         if (dialog instanceof JDialog) {
  162.         ((JDialog) dialog).setBackground(UIManager.getColor("window"));
  163.         ((JDialog) dialog).setResizable(false);
  164.         break;
  165.         }
  166.         dialog = dialog.getParent();
  167.     }
  168.     }
  169.     
  170.     /**
  171.      * Creates and adds a JLabel representing the icon returned from
  172.      * <code>getIcon</code> to <code>top</code>. This is messaged from
  173.      * <code>createBody</code>
  174.      */
  175.     protected void addIcon(Container top) {
  176.     /* Create the icon. */
  177.     Icon                  sideIcon = getIcon();
  178.  
  179.     if (sideIcon != null) {
  180.         JLabel            iconLabel = new JLabel(sideIcon);
  181.  
  182.         iconLabel.setVerticalAlignment(SwingConstants.TOP);
  183.         iconLabel.setHorizontalAlignment(SwingConstants.LEFT);
  184.         top.add(iconLabel, "West");
  185.         hasIcon = true;
  186.     } else
  187.         hasIcon = false;
  188.     }
  189.  
  190.     /**
  191.      * Messaged from validateComponent to create a Container containing the
  192.      * body of the message. The icon is the created by calling
  193.      * <code>addIcon</code>.
  194.      */
  195.     protected Container createBody() {
  196.     Container          top = new Container() {
  197.         public Insets getInsets() {
  198.         return getBodyInsets();
  199.         }
  200.     };
  201.  
  202.     top.setLayout(new BorderLayout());
  203.  
  204.     /* Fill the body. */
  205.     GridBagConstraints cons = new GridBagConstraints();
  206.     Container          body = new Container() {};
  207.     Container          realBody = new Container() {};
  208.  
  209.     realBody.setLayout(new BorderLayout());
  210.     realBody.add(new Container() {
  211.         public Dimension getPreferredSize() {
  212.         return (hasIcon) ? new Dimension(23, 1) : new Dimension(1, 1);
  213.         }
  214.     }, BorderLayout.WEST);
  215.  
  216.     Container          anotherBody = new Container() {};
  217.     anotherBody.setLayout(new BorderLayout());
  218.     anotherBody.add(body, BorderLayout.NORTH);
  219.     realBody.add(anotherBody, BorderLayout.CENTER);
  220.     //    realBody.add(body, BorderLayout.CENTER);
  221.  
  222.     body.setLayout(new GridBagLayout());
  223.     cons.gridx = cons.gridy = 0;
  224.     cons.gridwidth = GridBagConstraints.REMAINDER;
  225.     cons.gridheight = 1;
  226.     cons.anchor = GridBagConstraints.WEST;
  227.     cons.insets = new Insets(0,0,3,0);
  228.  
  229.     appendDescription(body, cons, getMessage(),
  230.               getMaxCharactersPerLineCount(), false);
  231.     top.add(realBody, BorderLayout.CENTER);
  232.  
  233.     addIcon(top);
  234.     return top;
  235.     }
  236.  
  237.  
  238.  
  239.     /**
  240.      * Returns the maximum number of characters to place on a line.
  241.      */
  242.     public int getMaxCharactersPerLineCount() {
  243.         int max = optionPane.getMaxCharactersPerLineCount();
  244.         if (max == Integer.MAX_VALUE)
  245.         return 60;
  246.     else
  247.         return max;
  248.     }
  249.  
  250.     /**
  251.      * Returns the insets to be used for the body, the body contains both
  252.      * the image and the actual message.
  253.      */
  254.     protected Insets getBodyInsets() {
  255.     return new Insets(0, 7, 0, 6);
  256.     }
  257.  
  258.  
  259.     /**
  260.      * Returns false. This is queried to determine if the buttons should
  261.      * be sized to the same width.
  262.      */
  263.     public boolean getSizeButtonsToSameWidth() {
  264.     return false;
  265.     }
  266.  
  267.     /**
  268.      * Creates the appropriate object to represent each of the objects in
  269.      * <code>buttons</code> and adds it to <code>container</code>. This
  270.      * differs from appendDescription in that it will recurse on
  271.      * <code>buttons</code> and that if button is not a Component
  272.      * it will create an instance of JButton, that when pressed will
  273.      * invoke <code>createdButtonFired</code> with the appropriate
  274.      * index.
  275.      */
  276.     protected void appendButtons(Container container, Object[] buttons,
  277.                  int initialIndex) {
  278.     if(buttons != null && buttons.length > 0) {
  279.         boolean            sizeButtonsToSame = getSizeButtonsToSameWidth();
  280.         boolean            createdAll = true;
  281.         int                numButtons = buttons.length;
  282.         JButton[]          createdButtons = null;
  283.         int                maxWidth = 0;
  284.  
  285.         if(sizeButtonsToSame)
  286.         createdButtons = new JButton[numButtons];
  287.  
  288.         for(int counter = 0; counter < numButtons; counter++) {
  289.         Object       anO = buttons[counter];
  290.         Component    newComponent;
  291.  
  292.         if(anO instanceof Component) {
  293.             createdAll = false;
  294.             newComponent = (Component)anO;
  295.             container.add(newComponent);
  296.             hasCustomComponents = true;
  297.         }
  298.         else {
  299.             JButton      aButton;
  300.  
  301.             if(anO instanceof Icon)
  302.             aButton = new JButton((Icon)anO);
  303.             else
  304.             aButton = new JButton(anO.toString());
  305.             container.add(aButton);
  306.  
  307.             final int       buttonIndex = counter;
  308.  
  309.             aButton.addActionListener(new ActionListener() {
  310.             public void actionPerformed(ActionEvent e) {
  311.                 createdButtonFired(buttonIndex);
  312.             }
  313.             });
  314.             newComponent = aButton;
  315.         }
  316.         if(sizeButtonsToSame && createdAll && 
  317.            (newComponent instanceof JButton)) {
  318.             createdButtons[counter] = (JButton)newComponent;
  319.             maxWidth = Math.max(maxWidth,
  320.                     newComponent.getMinimumSize().width);
  321.         }
  322.         if(counter == initialIndex) {
  323.             initialFocusComponent = newComponent;
  324.         }
  325.         }
  326.         ((MacSyncingLayoutManager)container.getLayout()).
  327.                       setSyncsAll((sizeButtonsToSame && createdAll));
  328.         /* Set the padding, windows seems to use 8 if <= 2 components,
  329.            otherwise 4 is used. It may actually just be the size of the
  330.            buttons is always the same, not sure. */
  331.         if(sizeButtonsToSame && createdAll) {
  332.         JButton               aButton;
  333.         int                   padSize;
  334.  
  335.         if(numButtons <= 2)
  336.             padSize = 8;
  337.         else
  338.             padSize = 4;
  339.         for(int counter = 0; counter < numButtons; counter++) {
  340.             aButton = createdButtons[counter];
  341.             aButton.setMargin(new Insets(2, padSize, 2, padSize));
  342.         }
  343.         }
  344.     }
  345.     }
  346.  
  347.     /**
  348.      * Creates and returns a Container containin the buttons. The buttons
  349.      * are created by calling <code>getButtons</code>.
  350.      */
  351.     protected Container createButtons() {
  352.     /* And the bottom for all the buttons. */
  353.     Container    b = new Container() {
  354.         public Insets getInsets() {
  355.         return getButtonInsets();
  356.         }
  357.     };
  358.  
  359.     b.setLayout(new MacSyncingLayoutManager(true, 13));
  360.     appendButtons(b, getButtons(), getInitialIndex());
  361.  
  362.     // move everything over to the right
  363.     Container outerContainer = new Container() {};
  364.     outerContainer.setLayout(new BorderLayout());
  365.     outerContainer.add(new Container() {}, BorderLayout.CENTER);
  366.     outerContainer.add(b, BorderLayout.EAST);
  367.     
  368.     ((MacSyncingLayoutManager)b.getLayout()).setCentersChildren(true);
  369.     ((MacSyncingLayoutManager)b.getLayout()).setMinButtonWidth(58);
  370.         
  371.     return outerContainer;
  372.     }
  373.  
  374.     /**
  375.      * Returns the insets to be used in the Container housing the buttons.
  376.      */
  377.     protected Insets getButtonInsets() {
  378.     return new Insets(11, 16, 0, 6);
  379.     }
  380.  
  381.     /**
  382.      * Returns the minumum size of a button in a dialog for this look & feel.
  383.      */
  384.     protected int getMinimumButtonWidth() {
  385.     return 58;
  386.     }
  387.  
  388.     /**
  389.      * MacSyncingLayoutManager acts similiar to FlowLayout. It lays out all
  390.      * components from left to right. If syncsAll is true, the widths
  391.      * of each component will be set to the largest preferred size width.
  392.      */
  393.     protected static class MacSyncingLayoutManager implements LayoutManager,
  394.           Serializable {
  395.     protected boolean           syncsAll;
  396.     protected int               padding;
  397.         /** If true, children are lumped together in parent. */
  398.     protected boolean           centersChildren;
  399.     protected int               minButtonWidth;
  400.  
  401.     public MacSyncingLayoutManager(boolean syncsAll, int padding) {
  402.         this.syncsAll = syncsAll;
  403.         this.padding = padding;
  404.         this.minButtonWidth = 0;
  405.         centersChildren = true;
  406.     }
  407.  
  408.     public void setSyncsAll(boolean newValue) {
  409.         syncsAll = newValue;
  410.     }
  411.  
  412.     public boolean getSyncsAll() {
  413.         return syncsAll;
  414.     }
  415.  
  416.     public void setPadding(int newPadding) {
  417.         this.padding = newPadding;
  418.     }
  419.  
  420.     public int getPadding() {
  421.         return padding;
  422.     }
  423.  
  424.         public void setCentersChildren(boolean newValue) {
  425.         centersChildren = newValue;
  426.     }
  427.  
  428.         public boolean getCentersChildren() {
  429.         return centersChildren;
  430.     }
  431.  
  432.     public void setMinButtonWidth(int minButtonWidth) {
  433.         this.minButtonWidth = minButtonWidth;
  434.     }
  435.  
  436.     public int getMinButtonWidth() {
  437.         return minButtonWidth;
  438.     }
  439.  
  440.     public void addLayoutComponent(String string, Component comp) {
  441.     }
  442.  
  443.     public void layoutContainer(Container container) {
  444.         Component[]      children = container.getComponents();
  445.  
  446.         if(children != null && children.length > 0) {
  447.         int               numChildren = children.length;
  448.         Dimension[]       sizes = new Dimension[numChildren];
  449.         int               counter;
  450.         int               yLocation = container.getInsets().top;
  451.  
  452.         if (syncsAll) {
  453.             int           maxWidth = minButtonWidth;
  454.  
  455.             for(counter = 0; counter < numChildren; counter++) {
  456.             sizes[counter] = children[counter].getPreferredSize();
  457.             maxWidth = Math.max(maxWidth, sizes[counter].width);
  458.             }
  459.  
  460.             int      xLocation;
  461.             int      xOffset;
  462.  
  463.             if (getCentersChildren()) {
  464.             xLocation = (container.getSize().width -
  465.                       (maxWidth * numChildren +
  466.                        (numChildren - 1) * padding)) / 2;
  467.             xOffset = padding + maxWidth;
  468.             }
  469.             else {
  470.             if(numChildren > 1) {
  471.                 xLocation = 0;
  472.                 xOffset = (container.getSize().width -
  473.                        (maxWidth * numChildren)) /
  474.                 (numChildren - 1) + maxWidth;
  475.             }
  476.             else {
  477.                 xLocation = (container.getSize().width -
  478.                      maxWidth) / 2;
  479.                 xOffset = 0;
  480.             }
  481.             }
  482.             for(counter = 0; counter < numChildren; counter++) {
  483.             children[counter].setBounds(xLocation, yLocation,
  484.                             maxWidth,
  485.                             sizes[counter].height);
  486.             xLocation += xOffset;
  487.             }
  488.         }
  489.         else {
  490.             int          totalWidth = 0;
  491.  
  492.             for(counter = 0; counter < numChildren; counter++) {
  493.             sizes[counter] = children[counter].getPreferredSize();
  494.             sizes[counter].width = Math.max(sizes[counter].width, minButtonWidth);
  495.             totalWidth += sizes[counter].width;
  496.             }
  497.             totalWidth += ((numChildren - 1) * padding);
  498.  
  499.             boolean      cc = getCentersChildren();
  500.             int          xOffset;
  501.             int          xLocation;
  502.  
  503.             if(cc) {
  504.             xLocation = (container.getSize().width -
  505.                           totalWidth) / 2;
  506.             xOffset = padding;
  507.             }
  508.             else {
  509.             if(numChildren > 1) {
  510.                 xOffset = (container.getSize().width -
  511.                        totalWidth) / (numChildren - 1);    
  512.             xLocation = 0;
  513.             }
  514.             else {
  515.                 xLocation = (container.getSize().width -
  516.                      totalWidth) / 2;
  517.                 xOffset = 0;
  518.             }
  519.             }
  520.  
  521.             for(counter = 0; counter < numChildren; counter++) {
  522.             children[counter].setBounds(xLocation, yLocation,
  523.                  sizes[counter].width, sizes[counter].height);
  524.             xLocation += xOffset + sizes[counter].width;
  525.             }
  526.         }
  527.         }
  528.     }
  529.  
  530.     public Dimension minimumLayoutSize(Container c) {
  531.         if(c != null) {
  532.         Component[]       children = c.getComponents();
  533.  
  534.         if(children != null && children.length > 0) {
  535.             Dimension     aSize;
  536.             int           numChildren = children.length;
  537.             int           height = 0;
  538.             Insets        cInsets = c.getInsets();
  539.             int           extraHeight = cInsets.top + cInsets.bottom;
  540.  
  541.             if(syncsAll) {
  542.             int              maxWidth = minButtonWidth;
  543.  
  544.             for(int counter = 0; counter < numChildren; counter++){
  545.                 aSize = children[counter].getPreferredSize();
  546.                 height = Math.max(height, aSize.height);
  547.                 maxWidth = Math.max(maxWidth, aSize.width);
  548.             }
  549.             return new Dimension(maxWidth * numChildren + 
  550.                          (numChildren - 1) * padding,
  551.                          extraHeight + height);
  552.             }
  553.             else {
  554.             int        totalWidth = 0;
  555.  
  556.             for(int counter = 0; counter < numChildren; counter++){
  557.                 aSize = children[counter].getPreferredSize();
  558.                 height = Math.max(height, aSize.height);
  559.                 totalWidth += Math.max(aSize.width, minButtonWidth);
  560.             }
  561.             totalWidth += ((numChildren - 1) * padding);
  562.             return new Dimension(totalWidth, extraHeight + height);
  563.             }
  564.         }
  565.         }
  566.         return new Dimension(0, 0);
  567.     }
  568.  
  569.     public Dimension preferredLayoutSize(Container c) {
  570.         return minimumLayoutSize(c);
  571.     }
  572.  
  573.     public void removeLayoutComponent(Component c) { }
  574.     }
  575. }
  576.